#include "EventHttpClient.h"
#include "Connection.h"
#include "Connection.h"
#include "Service.h"
//#include "GameUtil.h"
#include "http_parser.h"
#include "StringUtil.h"
#include "EventDns.h"


static http_parser_settings s_parserSettings = {
	NULL, //http_cb      on_message_begin;
	NULL, //http_data_cb on_url;
	NULL,//http_cb      on_status_complete;
	&EventHttpClient::http_response_on_header_field, //http_data_cb on_header_field;
	&EventHttpClient::http_response_on_header_value, //http_data_cb on_header_value;
	&EventHttpClient::http_response_on_header_complete, //http_cb      on_headers_complete;
	&EventHttpClient::http_response_on_body, //http_data_cb on_body;
	&EventHttpClient::http_response_on_message_complete //http_cb      on_message_complete;
};

int EventHttpClient::http_response_on_header_complete(http_parser* parser) {
	return 0;
}

int EventHttpClient::http_response_on_message_complete(http_parser* parser) {
	EventHttpClient* client = (EventHttpClient*)parser->data;
	
	if (client->m_handler) {
		client->m_handler->onHttpClientComplete(client, parser->status_code, client->m_response);
	}
	client->m_isComplete = true;
	return 0;
}

int EventHttpClient::http_response_on_header_value(http_parser* parser, const char* at, size_t len) {
	return 0;
}

int EventHttpClient::http_response_on_header_field(http_parser* parser, const char* at, size_t len) {
	return 0;
}

int EventHttpClient::http_response_on_body(http_parser* parser, const char* at, size_t len) {
	EventHttpClient* client = (EventHttpClient*)parser->data;
	client->m_response.append(at, len);
	return 0;
}



bool EventHttpClient::ParseUrl() {
	http_parser_url parser_url;

	if (http_parser_parse_url(m_url.c_str(), m_url.size(), false, &parser_url) != 0) {
		return false;
	}

	if (parser_url.field_set &  (1 << UF_PATH)) {
		int len = parser_url.field_data[UF_PATH].len;
		m_path.resize(len);
		strncpy((char*)m_path.c_str(), m_url.c_str() + parser_url.field_data[UF_PATH].off, len);
	}

	if (parser_url.field_set &  (1 << UF_SCHEMA)) {
		int len = parser_url.field_data[UF_SCHEMA].len;
		m_scheme.resize(len);
		strncpy((char*)m_scheme.c_str(), m_url.c_str() + parser_url.field_data[UF_SCHEMA].off, len);
	}

	if (parser_url.field_set & (1 << UF_HOST)) {
		int len = parser_url.field_data[UF_HOST].len;
		m_host.resize(len);
		strncpy((char*)m_host.c_str(), m_url.c_str() + parser_url.field_data[UF_HOST].off, len);
		this->m_mapRequestHeaders["Host"] = m_host;
	}

	if (parser_url.field_set & (1 << UF_QUERY)) {
		int len = parser_url.field_data[UF_QUERY].len;
		m_query.resize(len);
		strncpy((char*)m_query.c_str(), m_url.c_str() + parser_url.field_data[UF_QUERY].off, len);
	}
	
	if (parser_url.field_set & (1 << UF_FRAGMENT)) {
		int len = parser_url.field_data[UF_FRAGMENT].len;
		m_flagment.resize(len);
		strncpy((char*)m_flagment.c_str(), m_url.c_str() + parser_url.field_data[UF_FRAGMENT].off, len);
	}
	
	if (parser_url.field_set & (1 << UF_PORT)) {
		int len = parser_url.field_data[UF_PORT].len;
		m_port.resize(len);
		strncpy((char*)m_port.c_str(), m_url.c_str() + parser_url.field_data[UF_PORT].off, len);
	} else if (m_scheme == "https") {
		m_port = "443";
		this->m_isTls = true;
	}

	return true;

}

void EventHttpClient::onConnected(Connection * conn)
{
	string method = m_method.empty() ? "GET" : m_method;
	string fullPath = m_path;

	if(!m_query.empty()) {
		fullPath += "?" + m_query;
	}
	string request = FrameworkStringUtil::format("%s %s HTTP/1.1\r\n", method.c_str(), fullPath.c_str());
	if(m_method == "POST") {
		m_mapRequestHeaders["Content-Length"] = FrameworkStringUtil::format("%d", m_postData.size());
	}
	for (std::map<string, string>::iterator iter = m_mapRequestHeaders.begin(); iter != m_mapRequestHeaders.end(); iter++) {
		request += FrameworkStringUtil::format("%s: %s\r\n", iter->first.c_str(), iter->second.c_str());
	}
	request += "\r\n";
	if(m_method == "POST" && m_postData.size()) {
		request.append(m_postData.c_str(), m_postData.size());
	}
	conn->sendData((char*)request.c_str(), request.size());	
}

void EventHttpClient::onClose(Connection * conn)
{
	if (m_handler) {
		m_handler->onHttpClientComplete(this, -1, "");
	}
}

void EventHttpClient::onData(Connection * conn)
{
	http_parser* parser = m_parser;
	bufferevent* bev = conn->getBev();
	int len = evbuffer_get_length(bev->input);
	char* data = (char*)evbuffer_pullup(bev->input, len);
	size_t lenParse = http_parser_execute(m_parser, &s_parserSettings, (const char*)data, len);
	if (parser->http_errno != HPE_OK) {
		if (m_handler) {
			m_handler->onHttpClientComplete(this, -1, "");
		}
		delete parser;
	} 

	evbuffer_drain(bev->input, len);

	if(this->m_isComplete) {
		delete this;
	}
}

EventHttpClient::~EventHttpClient()
{
	if (m_connection) {
		delete m_connection;
		m_connection = NULL;
	}
	this->cancle();
}

EventHttpClient * EventHttpClient::create(Service * service, const string & url,  EventHttpClientHandler* handler)
{
	EventHttpClient* client = new EventHttpClient;
	client->m_url = url;
	client->m_port = "80";
	client->m_service = service;
	client->m_parser = new http_parser;
	client->m_timeout = NULL;
	http_parser_init(client->m_parser, HTTP_RESPONSE);
	client->m_parser->data = client;
	client->m_handler = handler;
	client->m_dns = NULL;
	client->m_connection = NULL;
	client->m_isComplete = false;
	return client;
}

bool EventHttpClient::commit()
{
	if (!ParseUrl()) {
		return false;
	}
	m_dns = EventDns::query(m_service, m_host, this);
	return true;
}

void EventHttpClient::cancle()
{
	if(m_parser) {
		delete m_parser;
		m_parser = NULL;
	}

	if (m_connection) {
		m_connection->close();
		m_connection = NULL;
	}

	if(m_dns) {
		delete m_dns;
		m_dns = NULL;
	}

	if(m_timeout) {
		evtimer_del(m_timeout);
		event_free(m_timeout);
		m_timeout = NULL;
	}
}

void EventHttpClient::setMethod( const std::string& method )
{
	m_method = method;
}

void EventHttpClient::addHeader( const std::string& key, const std::string& value )
{
	m_mapRequestHeaders[key] = value;
}

void EventHttpClient::setPostData( const std::string& data )
{
	m_postData = data;
}

void EventHttpClient::onDnsResolve( EventDns* dns, bool isSuccess, const std::string& ip )
{
	this->m_dns = NULL;
	if(isSuccess) {
		m_connection = new Connection(m_service);
		m_connection->setHandler(this);
		m_connection->connect(ip, atoi(m_port.c_str()));
	} else {
		if (m_handler) {
			m_handler->onHttpClientComplete(this, -1, "");
		}
	}
}

void EventHttpClient::setArgs( void* args )
{
	m_args = args;
}

void* EventHttpClient::getArgs()
{
	return m_args;
}

void EventHttpClient::onTimeout( int fd, short event, void* args )
{
	EventHttpClient* client = (EventHttpClient*)args;
	client->m_handler->onHttpClientComplete(client, -1, "");
	client->cancle();
	delete client;
}

